/*
 * Window.h
 *
 *  Created on: 2012-8-27
 *      Author: yangentao@gmail.com
 */

#ifndef WINDOW_H_
#define WINDOW_H_

#include "headers.h"
#include <Windows.h>
#include <Windowsx.h>
#include <CommCtrl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>

#include <vector>
#include <algorithm>

#include <boost/shared_ptr.hpp>
#include <boost/signals2.hpp>
#include <boost/function.hpp>

#include "Graphic.h"
#include "WndUtil.h"

#include "Message.h"
#include "WindowListener.h"
#include "WindowListenerAdapter.h"

#include "Layout.h"

using namespace std;

//enum LayoutParamType;
//class LayoutParam;
//class LinnerLayoutParam;
//class Layout;
class Window;

Window* getSoyWindow(HWND hWnd);

struct LastMsgResult {
	typedef MsgResult result_type;
	template<typename InputIterator>
	MsgResult operator()(InputIterator first, InputIterator last) const {
		if (first == last)
			return MsgResult();
		MsgResult val = *first++;
		while (first != last) {
			if (first->enable) {
				val = *first;
			}
			++first;
		}
		return val;
	}
};

class WindowParam {
public:
	HWND parent;
	LPCTSTR text;
	Rect rect;
	DWORD style;
	DWORD exStyle;
public:
	LPCTSTR className;
public:
	WindowParam(bool doubleClick = false);
public:

	void FrameParam(LPCTSTR text_, Rect rect_);
	void ChildParam(HWND parent, Rect rect);
	void NoClipChildParam(HWND parent, Rect rect);
	void PopupParam(HWND parent, Rect rect);

};

//event process order:
//1: Window::onMessage
//2: Window::Events
//3: Window::addMessageHandler/addMessageListener
class Window: public WndUtil, public WindowListener {
	typedef WndUtil Super;
	typedef boost::signals2::signal<
			MsgResult(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam),
			LastMsgResult> MessageSignal;
	typedef MessageSignal::slot_type MessageHandler;
public:
	Window();
	virtual ~Window();
protected:
	bool create(WindowParam param);
	bool createChild(WindowParam param);
	bool createFrame(WindowParam param);
	bool createPopup(WindowParam param);
	void subclassWindow(HWND w);
public:
	virtual MsgResult onMessage(HWND hWnd, UINT uMsg, WPARAM wParam,
			LPARAM lParam);
	//will not send message to hWnd, only call the messgage handlers
	MsgResult fireOnMessage(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
	boost::signals2::connection addMessageHandler(
			const MessageHandler& msgHandler);
	boost::signals2::connection addMessageListener(WindowListener* listener);
	void clearWindowListeners();
public:
	void addStyle(DWORD style);
	void removeStyle(DWORD style);
	void addExStyle(DWORD exStyle);
	void removeExStyle(DWORD exStyle);
public:
	void setTabStop(bool tab);
	void setAutoCapture(bool autoCapture);
	void setAutoFocus(bool autoFocus);
	void setAutoTrackHover(bool track, DWORD hoverTime = HOVER_DEFAULT);
public:
	Vector<Window*> getChildren(bool withLayoutParam, LayoutParamType type);

	void setLayoutParam(boost::shared_ptr<LayoutParam> layoutParam);
	void setLayoutParam(boost::shared_ptr<RelativeParam> param);
	void setLayoutParam(boost::shared_ptr<LinnerParam> param);

	LayoutParam* getLayoutParam();
	RelativeParam* getRelativeParam();
	LinnerParam* getLinnerParam();

	void setLayout(boost::shared_ptr<Layout> layout);
	void setLayout(boost::shared_ptr<LinnerLayout> linnerLayout);
	void setLayout(boost::shared_ptr<RelativeLayout> relativeLayout);

	Layout* getLayout();
	LinnerLayout* getLinnerLayout();
	RelativeLayout* getRelativeLayout();
private:
	void onLayout();
public:
	WindowListenerAdapter Events;
private:
	MessageSignal msgSignal;
private:
	bool autoCapture;
	bool autoFocus;
	bool trackHover;
	DWORD hoverTime;
	bool tracked;
	bool fireMouseEnter;
private:
	boost::shared_ptr<LayoutParam> layoutParam;
	boost::shared_ptr<Layout> layout;
private:
	DWORD style;
	DWORD exStyle;
};

void addWindowCreateHook();
void removeWindowCreateHook();

#endif /* WINDOW_H_ */
